package org.flexthinker.binding.validation.support
{
    import org.flexthinker.binding.validation.ValidationListener;
    import org.flexthinker.binding.validation.ValidationResults;
    import org.flexthinker.binding.validation.ValidationResultsModel;

    import flash.utils.Dictionary;

    import mx.events.ValidationResultEvent;

    /**
     * Contains ValidationResults and notifies listeners when results change.
     */
    public class DefaultValidationResultsModel implements ValidationResultsModel
    {
        private var currentValidationResults:ValidationResults = new DefaultValidationResults();

        private var validationListeners:Vector.<ValidationListener> = new Vector.<ValidationListener>();

        /**
         * For each property, the dictionary contains an array of Listeners
         */
        private var propertyValidationListeners:Dictionary = new Dictionary();

        public function DefaultValidationResultsModel()
        {
        }

        public function updateValidationResults( validationResults:ValidationResults ):void
        {
            if ( validationResults == null )
            {
                return;
            }
            if (currentValidationResults.getMessageCount() == 0 && validationResults.getMessageCount() == 0)
            {
                return;
            }
            currentValidationResults = validationResults;
            fireChangedEvents();
            for( var key:String in propertyValidationListeners )
            {
                fireValidationResultsChangedFor( key );
            }
        }

        // ------------------------------------
        //   ValidationResultsModel interface
        // ------------------------------------

        public function addValidationListener( listener:ValidationListener ):void
        {
            validationListeners.push( listener );
        }


        public function removeValidationListener( listener:ValidationListener ):void
        {
            var idx:int = validationListeners.indexOf( listener );
            if( idx >= 0 )
            {
                validationListeners.splice( idx, 1 );
            }
        }

        public function addValidationListenerForProperty( propertyName:String, listener:ValidationListener ):void
        {
            var propListeners:Vector.<ValidationListener> = propertyValidationListeners[propertyName] as Vector.<ValidationListener>;
            if( propListeners == null )
            {
                propListeners = new Vector.<ValidationListener>();
                propertyValidationListeners[propertyName] = propListeners;
            }
            propListeners.push( listener );
        }


        public function removeValidationListenerForProperty( propertyName:String, listener:ValidationListener ):void
        {
            var propListeners:Vector.<ValidationListener> = propertyValidationListeners[propertyName] as Vector.<ValidationListener>;
            if ( propListeners != null )
            {
                var idx:int = propListeners.indexOf(listener);
                if ( idx >= 0 )
                {
                    propListeners.splice(idx, 1);
                }
            }
        }

        // --------------------------------
        //   ValidationResults interface
        // --------------------------------

        public function getHasWarnings():Boolean
        {
            return currentValidationResults && currentValidationResults.getHasWarnings();
        }


        public function getHasErrors():Boolean
        {
            return currentValidationResults && currentValidationResults.getHasErrors();
        }


        public function getHasInfo():Boolean
        {
            return currentValidationResults && currentValidationResults.getHasInfo();
        }


        public function getMessagesForProperty( propertyName:String ):Vector.<ValidationResultEvent>
        {
            return currentValidationResults.getMessagesForProperty( propertyName );
        }


        public function getMessagesForSeverity( severity:String ):Vector.<ValidationResultEvent>
        {
            return currentValidationResults.getMessagesForSeverity(severity);
        }


        public function getMessageCountForSeverity( severity:String ):int
        {
            return currentValidationResults.getMessageCountForSeverity(severity);
        }


        public function getMessages():Vector.<ValidationResultEvent>
        {
            return currentValidationResults.getMessages();
        }


        public function getMessageCountForProperty( propertyName:String ):int
        {
            return currentValidationResults.getMessageCountForProperty(propertyName);
        }


        public function getMessageCount():int
        {
            return currentValidationResults.getMessageCount();
        }

        // -------------------
        //   internal methods
        // -------------------


        private function fireChangedEvents():void
        {
            fireValidationResultsChanged();
        }

        private function fireValidationResultsChangedFor( propertyName:String ):void
        {
            for each  ( var listener:ValidationListener in propertyValidationListeners[propertyName] )
            {
                listener.validationResultsChanged( new DefaultValidationResults( getMessagesForProperty( propertyName ) ) );
            }
        }

        private function fireValidationResultsChanged():void
        {
            for each ( var listener:ValidationListener in validationListeners )
            {
                listener.validationResultsChanged( currentValidationResults );
            }
        }


    }
}